Introduction

The dynamics of flight pricing is a subject that interests and affects travelers around the globe. According to ICAO’s statistics, the total number of passengers carried on scheduled services rose to 4.5 billion in 2019, which is 3.6 per cent increase from the previous year, while the number of departures reached 38.3 million in 2019, a 1.7 per cent increase [3]. The upward trend for air travel is expected to continue for each passing year which is why it is important for people to understand what factors are behind these flight prices. Understanding these factors could save them some money as they go to off to see their families or go on a well deserved break. In this report, we will be tackling the questions below:

  1. Does departure time affect the price of the air ticket? Which time has the cheapest and most expensive flight ticket?

  2. Does the duration of the flight affect the price of the air ticket?

  3. Will the price of the flights be affected by the days left?

Data

The data we used to investigate our questions is extracted from Clean_Dataset.csv in the Flight Price Prediction datasets from Kaggle. The dataset was sourced from https://www.kaggle.com/datasets/shubhambathwal/flight-price-prediction/data. The dataset is prepared and complied by Shubham Bathwa. The data in the dataset is collected from “Ease My Trip” website. Both data for economy class flight tickets and business class flight tickets that traveled between India’s top 6 metro cities are extracted from the website. The data was collected over a period of 50 days.

The dataset contains 300,153 entries, each representing a flight ticket from the “Ease My Trip” website. The dataset consists of 12 columns and each columns contains a flight information from the flight ticket. The information represented in the columns are airline company, flight code, source city, departure time, number of stops, arrival time, destination city, ticket class, flight duration, days left to the day of the flight, and price of the ticket. The dataset contains information on 6 unique airlines, 1,561 unique planes, 6 unique departure cities, 6 unique departure times, 6 unique arrival times, 6 unique destination cities, and 2 unique types of classes.

Data Cleaning and Pre-processing

The first column of the dataset represents the row numbers for each entry. As this information is not needed, the column containing the row numbers is removed. Several columns in the dataset, such as airline, flight, source city, departure time, stops, arrival time, destination city, and class, are of character type. These columns are factorized for easier data manipulation and analysis. The cleaned dataset now contains 11 columns, where 8 columns are the “factor” data type, and 3 are the double data type.

# Loading the data
data <- read_csv("archive/Clean_Dataset.csv")
New names:
• `` -> `...1`
Rows: 300153 Columns: 12
── Column specification ───────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (8): airline, flight, source_city, departure_time, stops, arrival_time, destination_city, c...
dbl (4): ...1, duration, days_left, price

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Remove unnecessary column and factorized columns
df <- data %>% select(-1) %>%
  mutate(across(c(airline, flight, source_city, departure_time, stops, arrival_time, destination_city, class), as.factor))

# Structure of dataset
str(df)
tibble [300,153 × 11] (S3: tbl_df/tbl/data.frame)
 $ airline         : Factor w/ 6 levels "Air_India","AirAsia",..: 5 5 2 6 6 6 6 6 3 3 ...
 $ flight          : Factor w/ 1561 levels "6E-102","6E-105",..: 1409 1388 1214 1560 1550 1542 1534 1544 1014 1015 ...
 $ source_city     : Factor w/ 6 levels "Bangalore","Chennai",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ departure_time  : Factor w/ 6 levels "Afternoon","Early_Morning",..: 3 2 2 5 5 5 5 1 2 1 ...
 $ stops           : Factor w/ 3 levels "one","two_or_more",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ arrival_time    : Factor w/ 6 levels "Afternoon","Early_Morning",..: 6 5 2 1 5 1 5 3 5 3 ...
 $ destination_city: Factor w/ 6 levels "Bangalore","Chennai",..: 6 6 6 6 6 6 6 6 6 6 ...
 $ class           : Factor w/ 2 levels "Business","Economy": 2 2 2 2 2 2 2 2 2 2 ...
 $ duration        : num [1:300153] 2.17 2.33 2.17 2.25 2.33 2.33 2.08 2.17 2.17 2.25 ...
 $ days_left       : num [1:300153] 1 1 1 1 1 1 1 1 1 1 ...
 $ price           : num [1:300153] 5953 5953 5956 5955 5955 ...
# Print the dataset
df

Exploratory Data Analysis

# Summary of the dataset
summary(df)
      airline           flight          source_city          departure_time          stops       
 Air_India: 80892   UK-706 :  3235   Bangalore:52061   Afternoon    :47794   one        :250863  
 AirAsia  : 16098   UK-772 :  2741   Chennai  :38700   Early_Morning:66790   two_or_more: 13286  
 GO_FIRST : 23173   UK-720 :  2650   Delhi    :61343   Evening      :65102   zero       : 36004  
 Indigo   : 43120   UK-836 :  2542   Hyderabad:40806   Late_Night   : 1306                       
 SpiceJet :  9011   UK-822 :  2468   Kolkata  :46347   Morning      :71146                       
 Vistara  :127859   UK-828 :  2440   Mumbai   :60896   Night        :48015                       
                    (Other):284077                                                               
        arrival_time    destination_city      class           duration       days_left 
 Afternoon    :38139   Bangalore:51068   Business: 93487   Min.   : 0.83   Min.   : 1  
 Early_Morning:15417   Chennai  :40368   Economy :206666   1st Qu.: 6.83   1st Qu.:15  
 Evening      :78323   Delhi    :57360                     Median :11.25   Median :26  
 Late_Night   :14001   Hyderabad:42726                     Mean   :12.22   Mean   :26  
 Morning      :62735   Kolkata  :49534                     3rd Qu.:16.17   3rd Qu.:38  
 Night        :91538   Mumbai   :59097                     Max.   :49.83   Max.   :49  
                                                                                       
     price       
 Min.   :  1105  
 1st Qu.:  4783  
 Median :  7425  
 Mean   : 20890  
 3rd Qu.: 42521  
 Max.   :123071  
                 

Visualizations & Interpretation

Question 1:

The boxplot shows that the medium of each departure time is relatively similar, ranging between 6,500 and 8,200 Rupees. Late-night departure time has a slightly lower medium than other departure times, which is 4499 Rupee. However, it is difficult to determine which departure time has the highest median based solely on the boxplot. Furthermore, the boxplot also illustrates that late-night departure time has the smallest interquartile range in price. In contrast, night departure time has the largest interquartile range in price, indicating greater price variability in flight tickets.

# Boxplot for flight prices by departure time
ggplot(df, aes(x = departure_time, y = price)) +
  geom_boxplot() +
  labs(title = "Flight Prices by Departure Time", x = "Departure Time", y = "Price") +
  theme_minimal()

After further analysis by calculating the mean price of the flight tickets, the late night departure time still has the cheapest flight tickets compared to other departure times, which is 9295.299 Rupee. On the other hand, night departure time has the most expensive flight tickets compared to the departure times, standing at the mean of 23062.147 Rupee.

# Calculate the mean price by departure time
df_departure <- df %>%
  group_by(departure_time) %>%
  summarize(mean_price = mean(price))

# Display the mean flight ticket price in a table
kable(df_departure, caption = "Mean Price by Departure Time")
Mean Price by Departure Time
departure_time mean_price
Afternoon 18179.203
Early_Morning 20370.677
Evening 21232.362
Late_Night 9295.299
Morning 21630.760
Night 23062.147

The histogram for night departure time prices demonstrates that the data is right-skewed, with more records of flight ticket prices on the lower end of the price range. However, the long tail of the histogram does extend to higher prices. The histogram also has a smaller peak, around 30,000 to 70,000 Rupees. This indicates that flight tickets with night departure times are typically in the price range of the two peaks.

# Get the entries for flights with Night departure times
df_night <- df %>% filter(departure_time == "Night")

# Plot histogram to investigate the distribution of the Night departure times flight price
ggplot(df_night, aes(x = price)) +
  geom_histogram(bins = 30, fill = "lightblue", color = "black") +
  labs(title = "Histogram of Night Flight Prices", x = "Price", y = "Frequency") +
  theme_minimal()

The histogram for late-night flight ticket prices illustrates that the data are heavily concentrated on the lower end. There are only a few isolated outliers where flight prices exceed 20,000 Rupees. The histogram also indicates that the frequency of late-night flight tickets was drastically lower than the night departure times of flight tickets.

# Get the entries for flights with Late Night departure times
df_late <- df %>% filter(departure_time == "Late_Night")

# Plot histogram to investigate the distribution of the Late Night departure times flight price
ggplot(df_late, aes(x = price)) +
  geom_histogram(bins =30, fill = "lightblue", color = "black") +
  labs(title = "Histogram of Late Night Flight Prices", x = "Price", y = "Frequency") +
  theme_minimal()

Question 2:

The scatterplot reveals that there are two different clusters present in the graph. Many of the points are concentrated on the lower left of the graph, which indicates that many of the flight tickets are lower in price and the flights have shorter duration. The positively sloped trendline also demonstrates that the duration of the flights and the price of flight tickets are positively correlated, where the longer the flight duration, the higher the price of the flight tickets.

# Plot scatter and density plot to investigate the relationship between duration and the prices of the flight 
ggplot(df, aes(x=duration, y=price)) + 
  geom_pointdensity(size = 0.5, alpha=0.05) + 
  scale_color_viridis_c() +
  geom_smooth(method = "lm", formula = y ~ x, color = "red") +
  labs(title = "Duration vs Price")

To further examine the relationship between the two clusters in the scatterplot, we coloured the points based on the class of the flight tickets. After applying the colour differentiation, the scatterplot shows that the two clusters belong to the two ticket classes. Pink cluster for business class flight tickets and blue cluster for economy flight tickets. Business flight tickets are generally more expensive than economy flight tickets. Thus, the cluster belonging to business flight tickets is slightly higher in the graph than economy flight tickets. The different ticket classes also explain the extensive range of prices for the same flight duration.

# Scatterplot to show the class of the flight tickets
ggplot(df, aes(x = duration, y = price, color = class)) +
  geom_point(size = 0.2, alpha = 0.3) +
  geom_smooth(method = "lm", formula = y ~ x, color = "red") +
  labs(title = "Duration vs Price", x = "Duration", y = "Price", color = "Class") +
  theme_minimal()

The scatter-density plot for business-class flight tickets reveals two main clusters of points. These clusters are centered around 25,000 and 60,000 Rupees. Both clusters fall within the duration range of 0 to 20 hours. The trend line in the graph highlights a positive relationship between flight duration and ticket price, where longer flights generally have higher prices for business-class tickets.

# Get the entries for business-class flight tickets
df_business <- df %>% filter(class == "Business")

# Plot hexagonal heatmap to investigate the relationship between duration and the prices of Business class flights
ggplot(df_business, aes(x = duration, y = price)) + 
  geom_pointdensity(size = 0.5, alpha = 0.5) + 
  scale_color_viridis_c() +
  geom_smooth(method = "lm", formula = y ~ x, color = "red") +
  labs(title = "Business Class's Duration vs Price", x = "Duration", y = "Price") +
  theme_minimal()

Similar to the scatter-density plot for business-class flight tickets, the graph has two main clusters for economy-class flight tickets. One cluster is located around the price level of 2500 Rupees, and the second cluster is around 50,000 Rupees. Most flights have durations shorter than 20 hours, as indicated by the higher density of points within this range. The trend line, similar to the previous graph, has a positive relationship between flight duration and ticket price.

# Get the entries for economy-class flight tickets
df_economy <- df %>% filter(class == "Economy")

# Plot hexagonal heatmap to investigate the relationship between duration and the prices of Economy class flights
ggplot(df_economy, aes(x = duration, y = price)) + 
  geom_pointdensity(size = 0.5, alpha = 0.5) + 
  scale_color_viridis_c() +
  geom_smooth(method = "lm", formula = y ~ x, color = "red") +
  labs(title = "Economy Class's Duration vs Price", x = "Duration", y = "Price") +
  theme_minimal()

Question 3:

Below, we created a scatter plot to see if there is a correlation between the days left from departure date and the price of the flight ticket. Further more, we also categorized the plot by the source and destination cities since we did not have individual flight numbers to track.

library(ggplot2)

# Adding a new column "source_dest" which is a combination of 
# source and destination city
combined_cities <- df %>% unite(source_dest, source_city, destination_city, sep = "_", remove = FALSE)

# Define the plotting function
plot_for_category <- function(cat, data) {
  subset_data <- subset(data, source_dest == cat)
  
  ggplot(subset_data, aes(x = days_left, y = price)) +
    geom_point(color = "blue") +
    geom_smooth(method = "lm", color = "red") +
    labs(
      title = paste("Plot for Category:", cat),
      x = "Days before Departure",
      y = "Price (Rupees)"
    ) +
    theme_minimal()
}

# Get unique categories
unique_categories <- unique(combined_cities$source_dest)

# Generate and store plots for each category
plots <- lapply(unique_categories, function(cat) plot_for_category(cat, combined_cities))

# Display all plots 
for (plot in plots) {
  plot + ylim(0, 100000)
  print(plot)
}
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'

Machine Learning Models

First, we will be splitting the dataset into the training and testing set to build our machine learning models. The training set will have 70 percent of the dataset and the testing set will have 30 percent of the dataset. We also chose to create a sample training data of 10000 rows, as it was taking our computers too long to compute the models using the larger dataset.

set.seed(123)
smp_size <- floor(0.7 * nrow(df))
row_index <- sample(1: nrow(df), size = smp_size)
train_smp <- df[row_index, ]
test_smp <- df[-row_index, ]
sample_data <- train_smp[sample(nrow(train_smp), 10000), ]

Tree-Based Models

The first model we are using to predict the flight prices is the tree-based model. In the model, we used categorical variable such as departure time of the flight and continuous variables such as duration of the flights and days left till the day of the flight. However, this model did not do well in predicting the prices as the mean absolute error is high and correlation is weak.

# Tree-Based Models
ar <- rpart(price ~ departure_time + duration + days_left, 
            train_smp)
preds <- predict(ar, test_smp)

# Calculate Mean Absolute Error (MAE)
mae <- mean(abs(preds - test_smp$price))
mae
[1] 18879.4
# Calculate correlation coefficient
cr <- cor(preds,test_smp$price)
cr
[1] 0.2592221
# Get the optimal cp value
optimal_cp <- ar$cptable[which.min(ar$cptable[,"xerror"]), "CP"]

# Prune the tree
pruned_tree <- prune(ar, cp = optimal_cp)

# Visualize the tree
rpart.plot(pruned_tree, box.palette = "Blues", main = "Simplified Decision Tree")

To make the model more accurate, we trained the tree-based model with more independent variables. After retraining the model, the model now produce predictions with extremely strong correlation and lower mean absolute error compare to the last model.

# Train model with more variables
ar2 <- rpart(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city,
            train_smp)
preds <- predict(ar2, test_smp)

# Calculate Mean Absolute Error (MAE)
mae <- mean(abs(preds - test_smp$price))
mae
[1] 4315.176
# Calculate correlation coefficient
cr <- cor(preds,test_smp$price)
cr
[1] 0.9569965

The plot shows that the flight class is the main predictor of the flight ticket’s price. The duration of the flight further influences the price of the business class flight.

# Get the optimal cp value
optimal_cp2 <- ar2$cptable[which.min(ar2$cptable[,"xerror"]), "CP"]

# Prune the tree
pruned_tree2 <- prune(ar2, cp = optimal_cp2)

# Visualize the tree
rpart.plot(pruned_tree2, box.palette = "Blues", main = "Simplified Decision Tree")

Linear Models

The next model we will be using to predict flight prices will be a linear model.

# Remove Flight column from data frame
sample_data <- subset(sample_data, select = -c(flight))

#Get formula for LM
dependent_vars <- setdiff(names(sample_data), "price")
formula <- as.formula(paste("price ~", paste(dependent_vars, collapse = " + ")))

# Build the linear model
linear_model <- lm(formula, data = sample_data)
# Get predictions and MAE
lm_preds <- predict(linear_model, test_smp)
lm_mae <- mean(abs(lm_preds - test_smp$price))
lm_mae
[1] 4560.298
# Calculate correlation coefficient
lm_cr <- cor(lm_preds,test_smp$price)
lm_cr
[1] 0.9543588

Support Vector Machine

Support vector machine is one of the model we are using to predict the price of the plane tickets. Independent variables such as departure time of the flight, duration of the flight, days left to the flight, number of stops, source city, airline, class, and destination_city are used to predict the price of the flight tickets. Three different kernel were used to find the suitable model. The radial SVM model performed the best in predicting the flight prices as the model has the smallest mean absolute error and highest correlation coefficient.

# linear svm model
s <- svm(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city, 
         sample_data, 
         kernel="linear")
s_preds <- predict(s, test_smp)
mae_s <- mean(abs(s_preds - test_smp$price))
mae_s
[1] 4183.375
cr_s <- cor(s_preds,test_smp$price)
cr_s
[1] 0.9514206
# radial svm model
r <- svm(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city, 
         sample_data, 
         kernel="radial")
r_preds <- predict(r, test_smp)
mae_r <- mean(abs(r_preds - test_smp$price))
mae_r
[1] 3139.727
cr_r <- cor(r_preds,test_smp$price)
cr_r
[1] 0.9731739
# poly svm model
poly <- svm(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city, 
            sample_data, 
            kernel="polynomial")
poly_preds <- predict(poly, test_smp)
mae_p <- mean(abs(poly_preds - test_smp$price))
mae_p
[1] 7739.832
cr_p <- cor(poly_preds,test_smp$price)
cr_p
[1] 0.91568

After tuning the radial SVM model, the model became more accurate as the mean absolute error decreased and the correlation coefficient increased. The best parameters for gamma and cost are 0.1 and 10, respectively. A smaller random subset of 5000 entries was used to train the fine-tuned model for efficiency.

# Take a smaller sample
sample_data2 <- train_smp[sample(nrow(train_smp), 5000), ]

# Find the best parameters
p <- tune.svm(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city, 
              data = sample_data2, 
              gamma=c(0.01, 0.1, 1), 
              cost=c(1, 5, 10) , 
              kernel = "radial") 

# Train the model with the best parameters
new_r <- svm(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city, 
             sample_data, 
             kernel="radial", 
             gamma=p$best.parameters$gamma, 
             cost=p$best.parameters$cost)
new_r_preds <- predict(new_r, test_smp)

# Calculate Mean Absolute Error (MAE)
new_mae_r <- mean(abs(new_r_preds - test_smp$price))
new_mae_r
[1] 2851.704
# Calculate correlation coefficient
new_cr_r <- cor(new_r_preds,test_smp$price)
new_cr_r
[1] 0.9783083

Conclusion

For this project we sought out to see if there are factors influencing the flight prices. For our first question, we ask if there was a correlation between the time of departure and the price of the tickets. From a number of visualizations that we did, we can see that there is definitely a correlation as late night tickets are usually the cheapest with very little variability in price with a mean price of 9295.3 Rupees. For the remaining departure times, we can see that there is not much difference in prices as the means of the rest of the departure times center around 21000 Rupees.

For our second question, we tried to see if there was a correlation between the duration of the flight and the ticket of the price. From just looking a the trend line from the scatter plot, we can see a positive correlation between the duration and the price of the ticket. Upon further inspection of the scatter plot, after differentiating the classes of the tickets, we can see the business class tickets get even more expensive with duration than economy tickets.

For our last question, we wanted to see if there was a relation between the days left from departure and the price of the ticket. We used a scatter plot categorized by source and destination city and for every plot we can see that there is a negative correlation between the price and the days left from departure, the further the departure date is the cheaper the tickets.

For our first tree model, we used only 3 indepandent variables (departure time, duration, days_left) with our target variable, price, to train our model. This did not lead to optimal results as we got a mean absolute error of 18879.4 and a correlation coefficient of 0.2592. So for our second tree model, we used all the variables in the data set to train the model and we received better results with a mean absolute error of 4315.176 and a correlation coefficient of 0.957.

For our linear model, we used all the variables in the data set to train the model and a mean absolute error of 4560.298 and a correlation coefficient of 0.954.

For our SVMs, first we trained 1 linear SVM, 1 radial SVM and 1 polynomial SVM using all the variables from the dataset. The table below shows the mean absolute value and the correlation coefficient for each of these models.

                Mean absolute value         Correlation coefficient 
Linear SVM       4183.375                         0.9514206                        
Radial SVM       3139.727                         0.9731739                       
Polynomial SVM   7739.832                         0.91568           

We decided to tune the Radial SVM to make it more accurate by using the best gamma and cost values. After tuning the models, the MAE decreased to 2851.704 and the correlation coefficient rose to 0.9783.

After evaluating all our models, we can see that Radial SVM has the best performance overall even before the tuning with a MAE of 3139.727 and a correlation coefficient of 0.973.

From this project, we can conclude that there are definitely factors such as departure time, duration and the days left from departure affecting the price of flight tickets.

Citations

[1] jan-glx, “Scatterplot with too many points,” Stack Overflow, Oct. 10, 2011. https://stackoverflow.com/questions/7714677/scatterplot-with-too-many-points/58523956#58523956

[2] “How to Prune a Tree in R?,” GeeksforGeeks, Jun. 13, 2024. https://www.geeksforgeeks.org/how-to-prune-a-tree-in-r/

[3] https://www.icao.int/annual-report-2019/Pages/the-world-of-air-transport-in-2019.aspx#:~:text=The%204.5%20billion%20scheduled%20passengers,some%2090%20million%20in%202040.&text=The%20world’s%20major%20manufacturers%20delivered,822%20new%20aircraft%20net%20orders.

LS0tCnRpdGxlOiAiRmxpZ2h0IFByaWNlIEFuYWx5c2lzIGFuZCBQcmVkaWN0aW9uIgphdXRob3I6ICJUaHVuZSBLeWFlIFNpbiBTdSAtIEIwMDg2ODgwNiwgWXVraSBMYXcgLSBCMDA4NjU4ODUiCmdyb3VwOiAiSGFuZ3J5IGFuZCBBbmdyeSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShrbml0cikKbGlicmFyeShnZ3BvaW50ZGVuc2l0eSkKbGlicmFyeShETXdSMikKbGlicmFyeShycGFydC5wbG90KQpsaWJyYXJ5KHJwYXJ0KQpsaWJyYXJ5KGUxMDcxKQpgYGAKCiMjIEludHJvZHVjdGlvbgoKVGhlIGR5bmFtaWNzIG9mIGZsaWdodCBwcmljaW5nIGlzIGEgc3ViamVjdCB0aGF0IGludGVyZXN0cyBhbmQgYWZmZWN0cyB0cmF2ZWxlcnMgYXJvdW5kIHRoZSBnbG9iZS4gQWNjb3JkaW5nIHRvIElDQU8ncyBzdGF0aXN0aWNzLCB0aGUgdG90YWwgbnVtYmVyIG9mIHBhc3NlbmdlcnMgY2FycmllZCBvbiBzY2hlZHVsZWQgc2VydmljZXMgcm9zZSB0byA0LjUgYmlsbGlvbiBpbiAyMDE5LCB3aGljaCBpcyAzLjYgcGVyIGNlbnQgaW5jcmVhc2UgZnJvbSB0aGUgcHJldmlvdXMgeWVhciwgd2hpbGUgdGhlIG51bWJlciBvZiBkZXBhcnR1cmVzIHJlYWNoZWQgMzguMyBtaWxsaW9uIGluIDIwMTksIGEgMS43IHBlciBjZW50IGluY3JlYXNlIFszXS4gVGhlIHVwd2FyZCB0cmVuZCBmb3IgYWlyIHRyYXZlbCBpcyBleHBlY3RlZCB0byBjb250aW51ZSBmb3IgZWFjaCBwYXNzaW5nIHllYXIgd2hpY2ggaXMgd2h5IGl0IGlzIGltcG9ydGFudCBmb3IgcGVvcGxlIHRvIHVuZGVyc3RhbmQgd2hhdCBmYWN0b3JzIGFyZSBiZWhpbmQgdGhlc2UgZmxpZ2h0IHByaWNlcy4gVW5kZXJzdGFuZGluZyB0aGVzZSBmYWN0b3JzIGNvdWxkIHNhdmUgdGhlbSBzb21lIG1vbmV5IGFzIHRoZXkgZ28gdG8gb2ZmIHRvIHNlZSB0aGVpciBmYW1pbGllcyBvciBnbyBvbiBhIHdlbGwgZGVzZXJ2ZWQgYnJlYWsuIEluIHRoaXMgcmVwb3J0LCB3ZSB3aWxsIGJlIHRhY2tsaW5nIHRoZSBxdWVzdGlvbnMgYmVsb3c6CgoxLiAgRG9lcyBkZXBhcnR1cmUgdGltZSBhZmZlY3QgdGhlIHByaWNlIG9mIHRoZSBhaXIgdGlja2V0PyBXaGljaCB0aW1lIGhhcyB0aGUgY2hlYXBlc3QgYW5kIG1vc3QgZXhwZW5zaXZlIGZsaWdodCB0aWNrZXQ/CgoyLiAgRG9lcyB0aGUgZHVyYXRpb24gb2YgdGhlIGZsaWdodCBhZmZlY3QgdGhlIHByaWNlIG9mIHRoZSBhaXIgdGlja2V0PwoKMy4gIFdpbGwgdGhlIHByaWNlIG9mIHRoZSBmbGlnaHRzIGJlIGFmZmVjdGVkIGJ5IHRoZSBkYXlzIGxlZnQ/CgojIyBEYXRhCgpUaGUgZGF0YSB3ZSB1c2VkIHRvIGludmVzdGlnYXRlIG91ciBxdWVzdGlvbnMgaXMgZXh0cmFjdGVkIGZyb20gQ2xlYW5fRGF0YXNldC5jc3YgaW4gdGhlIEZsaWdodCBQcmljZSBQcmVkaWN0aW9uIGRhdGFzZXRzIGZyb20gS2FnZ2xlLiBUaGUgZGF0YXNldCB3YXMgc291cmNlZCBmcm9tIDxodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL3NodWJoYW1iYXRod2FsL2ZsaWdodC1wcmljZS1wcmVkaWN0aW9uL2RhdGE+LiBUaGUgZGF0YXNldCBpcyBwcmVwYXJlZCBhbmQgY29tcGxpZWQgYnkgU2h1YmhhbSBCYXRod2EuIFRoZSBkYXRhIGluIHRoZSBkYXRhc2V0IGlzIGNvbGxlY3RlZCBmcm9tIOKAnEVhc2UgTXkgVHJpcOKAnSB3ZWJzaXRlLiBCb3RoIGRhdGEgZm9yIGVjb25vbXkgY2xhc3MgZmxpZ2h0IHRpY2tldHMgYW5kIGJ1c2luZXNzIGNsYXNzIGZsaWdodCB0aWNrZXRzIHRoYXQgdHJhdmVsZWQgYmV0d2VlbiBJbmRpYSdzIHRvcCA2IG1ldHJvIGNpdGllcyBhcmUgZXh0cmFjdGVkIGZyb20gdGhlIHdlYnNpdGUuIFRoZSBkYXRhIHdhcyBjb2xsZWN0ZWQgb3ZlciBhIHBlcmlvZCBvZiA1MCBkYXlzLgoKVGhlIGRhdGFzZXQgY29udGFpbnMgMzAwLDE1MyBlbnRyaWVzLCBlYWNoIHJlcHJlc2VudGluZyBhIGZsaWdodCB0aWNrZXQgZnJvbSB0aGUg4oCcRWFzZSBNeSBUcmlw4oCdIHdlYnNpdGUuIFRoZSBkYXRhc2V0IGNvbnNpc3RzIG9mIDEyIGNvbHVtbnMgYW5kIGVhY2ggY29sdW1ucyBjb250YWlucyBhIGZsaWdodCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBmbGlnaHQgdGlja2V0LiBUaGUgaW5mb3JtYXRpb24gcmVwcmVzZW50ZWQgaW4gdGhlIGNvbHVtbnMgYXJlIGFpcmxpbmUgY29tcGFueSwgZmxpZ2h0IGNvZGUsIHNvdXJjZSBjaXR5LCBkZXBhcnR1cmUgdGltZSwgbnVtYmVyIG9mIHN0b3BzLCBhcnJpdmFsIHRpbWUsIGRlc3RpbmF0aW9uIGNpdHksIHRpY2tldCBjbGFzcywgZmxpZ2h0IGR1cmF0aW9uLCBkYXlzIGxlZnQgdG8gdGhlIGRheSBvZiB0aGUgZmxpZ2h0LCBhbmQgcHJpY2Ugb2YgdGhlIHRpY2tldC4gVGhlIGRhdGFzZXQgY29udGFpbnMgaW5mb3JtYXRpb24gb24gNiB1bmlxdWUgYWlybGluZXMsIDEsNTYxIHVuaXF1ZSBwbGFuZXMsIDYgdW5pcXVlIGRlcGFydHVyZSBjaXRpZXMsIDYgdW5pcXVlIGRlcGFydHVyZSB0aW1lcywgNiB1bmlxdWUgYXJyaXZhbCB0aW1lcywgNiB1bmlxdWUgZGVzdGluYXRpb24gY2l0aWVzLCBhbmQgMiB1bmlxdWUgdHlwZXMgb2YgY2xhc3Nlcy4KCiMjIERhdGEgQ2xlYW5pbmcgYW5kIFByZS1wcm9jZXNzaW5nCgpUaGUgZmlyc3QgY29sdW1uIG9mIHRoZSBkYXRhc2V0IHJlcHJlc2VudHMgdGhlIHJvdyBudW1iZXJzIGZvciBlYWNoIGVudHJ5LiBBcyB0aGlzIGluZm9ybWF0aW9uIGlzIG5vdCBuZWVkZWQsIHRoZSBjb2x1bW4gY29udGFpbmluZyB0aGUgcm93IG51bWJlcnMgaXMgcmVtb3ZlZC4gU2V2ZXJhbCBjb2x1bW5zIGluIHRoZSBkYXRhc2V0LCBzdWNoIGFzIGFpcmxpbmUsIGZsaWdodCwgc291cmNlIGNpdHksIGRlcGFydHVyZSB0aW1lLCBzdG9wcywgYXJyaXZhbCB0aW1lLCBkZXN0aW5hdGlvbiBjaXR5LCBhbmQgY2xhc3MsIGFyZSBvZiBjaGFyYWN0ZXIgdHlwZS4gVGhlc2UgY29sdW1ucyBhcmUgZmFjdG9yaXplZCBmb3IgZWFzaWVyIGRhdGEgbWFuaXB1bGF0aW9uIGFuZCBhbmFseXNpcy4gVGhlIGNsZWFuZWQgZGF0YXNldCBub3cgY29udGFpbnMgMTEgY29sdW1ucywgd2hlcmUgOCBjb2x1bW5zIGFyZSB0aGUgImZhY3RvciIgZGF0YSB0eXBlLCBhbmQgMyBhcmUgdGhlIGRvdWJsZSBkYXRhIHR5cGUuCgpgYGB7cn0KIyBMb2FkaW5nIHRoZSBkYXRhCmRhdGEgPC0gcmVhZF9jc3YoImFyY2hpdmUvQ2xlYW5fRGF0YXNldC5jc3YiKQoKIyBSZW1vdmUgdW5uZWNlc3NhcnkgY29sdW1uIGFuZCBmYWN0b3JpemVkIGNvbHVtbnMKZGYgPC0gZGF0YSAlPiUgc2VsZWN0KC0xKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoYWlybGluZSwgZmxpZ2h0LCBzb3VyY2VfY2l0eSwgZGVwYXJ0dXJlX3RpbWUsIHN0b3BzLCBhcnJpdmFsX3RpbWUsIGRlc3RpbmF0aW9uX2NpdHksIGNsYXNzKSwgYXMuZmFjdG9yKSkKCiMgU3RydWN0dXJlIG9mIGRhdGFzZXQKc3RyKGRmKQoKIyBQcmludCB0aGUgZGF0YXNldApkZgpgYGAKCiMjIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMKCmBgYHtyfQojIFN1bW1hcnkgb2YgdGhlIGRhdGFzZXQKc3VtbWFyeShkZikKYGBgCgojIyBWaXN1YWxpemF0aW9ucyAmIEludGVycHJldGF0aW9uCgpRdWVzdGlvbiAxOgoKVGhlIGJveHBsb3Qgc2hvd3MgdGhhdCB0aGUgbWVkaXVtIG9mIGVhY2ggZGVwYXJ0dXJlIHRpbWUgaXMgcmVsYXRpdmVseSBzaW1pbGFyLCByYW5naW5nIGJldHdlZW4gNiw1MDAgYW5kIDgsMjAwIFJ1cGVlcy4gTGF0ZS1uaWdodCBkZXBhcnR1cmUgdGltZSBoYXMgYSBzbGlnaHRseSBsb3dlciBtZWRpdW0gdGhhbiBvdGhlciBkZXBhcnR1cmUgdGltZXMsIHdoaWNoIGlzIDQ0OTkgUnVwZWUuIEhvd2V2ZXIsIGl0IGlzIGRpZmZpY3VsdCB0byBkZXRlcm1pbmUgd2hpY2ggZGVwYXJ0dXJlIHRpbWUgaGFzIHRoZSBoaWdoZXN0IG1lZGlhbiBiYXNlZCBzb2xlbHkgb24gdGhlIGJveHBsb3QuIEZ1cnRoZXJtb3JlLCB0aGUgYm94cGxvdCBhbHNvIGlsbHVzdHJhdGVzIHRoYXQgbGF0ZS1uaWdodCBkZXBhcnR1cmUgdGltZSBoYXMgdGhlIHNtYWxsZXN0IGludGVycXVhcnRpbGUgcmFuZ2UgaW4gcHJpY2UuIEluIGNvbnRyYXN0LCBuaWdodCBkZXBhcnR1cmUgdGltZSBoYXMgdGhlIGxhcmdlc3QgaW50ZXJxdWFydGlsZSByYW5nZSBpbiBwcmljZSwgaW5kaWNhdGluZyBncmVhdGVyIHByaWNlIHZhcmlhYmlsaXR5IGluIGZsaWdodCB0aWNrZXRzLgoKYGBge3J9CiMgQm94cGxvdCBmb3IgZmxpZ2h0IHByaWNlcyBieSBkZXBhcnR1cmUgdGltZQpnZ3Bsb3QoZGYsIGFlcyh4ID0gZGVwYXJ0dXJlX3RpbWUsIHkgPSBwcmljZSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicyh0aXRsZSA9ICJGbGlnaHQgUHJpY2VzIGJ5IERlcGFydHVyZSBUaW1lIiwgeCA9ICJEZXBhcnR1cmUgVGltZSIsIHkgPSAiUHJpY2UiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKQWZ0ZXIgZnVydGhlciBhbmFseXNpcyBieSBjYWxjdWxhdGluZyB0aGUgbWVhbiBwcmljZSBvZiB0aGUgZmxpZ2h0IHRpY2tldHMsIHRoZSBsYXRlIG5pZ2h0IGRlcGFydHVyZSB0aW1lIHN0aWxsIGhhcyB0aGUgY2hlYXBlc3QgZmxpZ2h0IHRpY2tldHMgY29tcGFyZWQgdG8gb3RoZXIgZGVwYXJ0dXJlIHRpbWVzLCB3aGljaCBpcyA5Mjk1LjI5OSBSdXBlZS4gT24gdGhlIG90aGVyIGhhbmQsIG5pZ2h0IGRlcGFydHVyZSB0aW1lIGhhcyB0aGUgbW9zdCBleHBlbnNpdmUgZmxpZ2h0IHRpY2tldHMgY29tcGFyZWQgdG8gdGhlIGRlcGFydHVyZSB0aW1lcywgc3RhbmRpbmcgYXQgdGhlIG1lYW4gb2YgMjMwNjIuMTQ3IFJ1cGVlLgoKYGBge3J9CiMgQ2FsY3VsYXRlIHRoZSBtZWFuIHByaWNlIGJ5IGRlcGFydHVyZSB0aW1lCmRmX2RlcGFydHVyZSA8LSBkZiAlPiUKICBncm91cF9ieShkZXBhcnR1cmVfdGltZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fcHJpY2UgPSBtZWFuKHByaWNlKSkKCiMgRGlzcGxheSB0aGUgbWVhbiBmbGlnaHQgdGlja2V0IHByaWNlIGluIGEgdGFibGUKa2FibGUoZGZfZGVwYXJ0dXJlLCBjYXB0aW9uID0gIk1lYW4gUHJpY2UgYnkgRGVwYXJ0dXJlIFRpbWUiKQpgYGAKClRoZSBoaXN0b2dyYW0gZm9yIG5pZ2h0IGRlcGFydHVyZSB0aW1lIHByaWNlcyBkZW1vbnN0cmF0ZXMgdGhhdCB0aGUgZGF0YSBpcyByaWdodC1za2V3ZWQsIHdpdGggbW9yZSByZWNvcmRzIG9mIGZsaWdodCB0aWNrZXQgcHJpY2VzIG9uIHRoZSBsb3dlciBlbmQgb2YgdGhlIHByaWNlIHJhbmdlLiBIb3dldmVyLCB0aGUgbG9uZyB0YWlsIG9mIHRoZSBoaXN0b2dyYW0gZG9lcyBleHRlbmQgdG8gaGlnaGVyIHByaWNlcy4gVGhlIGhpc3RvZ3JhbSBhbHNvIGhhcyBhIHNtYWxsZXIgcGVhaywgYXJvdW5kIDMwLDAwMCB0byA3MCwwMDAgUnVwZWVzLiBUaGlzIGluZGljYXRlcyB0aGF0IGZsaWdodCB0aWNrZXRzIHdpdGggbmlnaHQgZGVwYXJ0dXJlIHRpbWVzIGFyZSB0eXBpY2FsbHkgaW4gdGhlIHByaWNlIHJhbmdlIG9mIHRoZSB0d28gcGVha3MuCgpgYGB7cn0KIyBHZXQgdGhlIGVudHJpZXMgZm9yIGZsaWdodHMgd2l0aCBOaWdodCBkZXBhcnR1cmUgdGltZXMKZGZfbmlnaHQgPC0gZGYgJT4lIGZpbHRlcihkZXBhcnR1cmVfdGltZSA9PSAiTmlnaHQiKQoKIyBQbG90IGhpc3RvZ3JhbSB0byBpbnZlc3RpZ2F0ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBOaWdodCBkZXBhcnR1cmUgdGltZXMgZmxpZ2h0IHByaWNlCmdncGxvdChkZl9uaWdodCwgYWVzKHggPSBwcmljZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzAsIGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgTmlnaHQgRmxpZ2h0IFByaWNlcyIsIHggPSAiUHJpY2UiLCB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgpUaGUgaGlzdG9ncmFtIGZvciBsYXRlLW5pZ2h0IGZsaWdodCB0aWNrZXQgcHJpY2VzIGlsbHVzdHJhdGVzIHRoYXQgdGhlIGRhdGEgYXJlIGhlYXZpbHkgY29uY2VudHJhdGVkIG9uIHRoZSBsb3dlciBlbmQuIFRoZXJlIGFyZSBvbmx5IGEgZmV3IGlzb2xhdGVkIG91dGxpZXJzIHdoZXJlIGZsaWdodCBwcmljZXMgZXhjZWVkIDIwLDAwMCBSdXBlZXMuIFRoZSBoaXN0b2dyYW0gYWxzbyBpbmRpY2F0ZXMgdGhhdCB0aGUgZnJlcXVlbmN5IG9mIGxhdGUtbmlnaHQgZmxpZ2h0IHRpY2tldHMgd2FzIGRyYXN0aWNhbGx5IGxvd2VyIHRoYW4gdGhlIG5pZ2h0IGRlcGFydHVyZSB0aW1lcyBvZiBmbGlnaHQgdGlja2V0cy4KCmBgYHtyfQojIEdldCB0aGUgZW50cmllcyBmb3IgZmxpZ2h0cyB3aXRoIExhdGUgTmlnaHQgZGVwYXJ0dXJlIHRpbWVzCmRmX2xhdGUgPC0gZGYgJT4lIGZpbHRlcihkZXBhcnR1cmVfdGltZSA9PSAiTGF0ZV9OaWdodCIpCgojIFBsb3QgaGlzdG9ncmFtIHRvIGludmVzdGlnYXRlIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIExhdGUgTmlnaHQgZGVwYXJ0dXJlIHRpbWVzIGZsaWdodCBwcmljZQpnZ3Bsb3QoZGZfbGF0ZSwgYWVzKHggPSBwcmljZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0zMCwgZmlsbCA9ICJsaWdodGJsdWUiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBMYXRlIE5pZ2h0IEZsaWdodCBQcmljZXMiLCB4ID0gIlByaWNlIiwgeSA9ICJGcmVxdWVuY3kiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKUXVlc3Rpb24gMjoKClRoZSBzY2F0dGVycGxvdCByZXZlYWxzIHRoYXQgdGhlcmUgYXJlIHR3byBkaWZmZXJlbnQgY2x1c3RlcnMgcHJlc2VudCBpbiB0aGUgZ3JhcGguIE1hbnkgb2YgdGhlIHBvaW50cyBhcmUgY29uY2VudHJhdGVkIG9uIHRoZSBsb3dlciBsZWZ0IG9mIHRoZSBncmFwaCwgd2hpY2ggaW5kaWNhdGVzIHRoYXQgbWFueSBvZiB0aGUgZmxpZ2h0IHRpY2tldHMgYXJlIGxvd2VyIGluIHByaWNlIGFuZCB0aGUgZmxpZ2h0cyBoYXZlIHNob3J0ZXIgZHVyYXRpb24uIFRoZSBwb3NpdGl2ZWx5IHNsb3BlZCB0cmVuZGxpbmUgYWxzbyBkZW1vbnN0cmF0ZXMgdGhhdCB0aGUgZHVyYXRpb24gb2YgdGhlIGZsaWdodHMgYW5kIHRoZSBwcmljZSBvZiBmbGlnaHQgdGlja2V0cyBhcmUgcG9zaXRpdmVseSBjb3JyZWxhdGVkLCB3aGVyZSB0aGUgbG9uZ2VyIHRoZSBmbGlnaHQgZHVyYXRpb24sIHRoZSBoaWdoZXIgdGhlIHByaWNlIG9mIHRoZSBmbGlnaHQgdGlja2V0cy4KCmBgYHtyfQojIFBsb3Qgc2NhdHRlciBhbmQgZGVuc2l0eSBwbG90IHRvIGludmVzdGlnYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBkdXJhdGlvbiBhbmQgdGhlIHByaWNlcyBvZiB0aGUgZmxpZ2h0IApnZ3Bsb3QoZGYsIGFlcyh4PWR1cmF0aW9uLCB5PXByaWNlKSkgKyAKICBnZW9tX3BvaW50ZGVuc2l0eShzaXplID0gMC41LCBhbHBoYT0wLjA1KSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIkR1cmF0aW9uIHZzIFByaWNlIikKYGBgCgpUbyBmdXJ0aGVyIGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0d28gY2x1c3RlcnMgaW4gdGhlIHNjYXR0ZXJwbG90LCB3ZSBjb2xvdXJlZCB0aGUgcG9pbnRzIGJhc2VkIG9uIHRoZSBjbGFzcyBvZiB0aGUgZmxpZ2h0IHRpY2tldHMuIEFmdGVyIGFwcGx5aW5nIHRoZSBjb2xvdXIgZGlmZmVyZW50aWF0aW9uLCB0aGUgc2NhdHRlcnBsb3Qgc2hvd3MgdGhhdCB0aGUgdHdvIGNsdXN0ZXJzIGJlbG9uZyB0byB0aGUgdHdvIHRpY2tldCBjbGFzc2VzLiBQaW5rIGNsdXN0ZXIgZm9yIGJ1c2luZXNzIGNsYXNzIGZsaWdodCB0aWNrZXRzIGFuZCBibHVlIGNsdXN0ZXIgZm9yIGVjb25vbXkgZmxpZ2h0IHRpY2tldHMuIEJ1c2luZXNzIGZsaWdodCB0aWNrZXRzIGFyZSBnZW5lcmFsbHkgbW9yZSBleHBlbnNpdmUgdGhhbiBlY29ub215IGZsaWdodCB0aWNrZXRzLiBUaHVzLCB0aGUgY2x1c3RlciBiZWxvbmdpbmcgdG8gYnVzaW5lc3MgZmxpZ2h0IHRpY2tldHMgaXMgc2xpZ2h0bHkgaGlnaGVyIGluIHRoZSBncmFwaCB0aGFuIGVjb25vbXkgZmxpZ2h0IHRpY2tldHMuIFRoZSBkaWZmZXJlbnQgdGlja2V0IGNsYXNzZXMgYWxzbyBleHBsYWluIHRoZSBleHRlbnNpdmUgcmFuZ2Ugb2YgcHJpY2VzIGZvciB0aGUgc2FtZSBmbGlnaHQgZHVyYXRpb24uCgpgYGB7cn0KIyBTY2F0dGVycGxvdCB0byBzaG93IHRoZSBjbGFzcyBvZiB0aGUgZmxpZ2h0IHRpY2tldHMKZ2dwbG90KGRmLCBhZXMoeCA9IGR1cmF0aW9uLCB5ID0gcHJpY2UsIGNvbG9yID0gY2xhc3MpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4yLCBhbHBoYSA9IDAuMykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCwgY29sb3IgPSAicmVkIikgKwogIGxhYnModGl0bGUgPSAiRHVyYXRpb24gdnMgUHJpY2UiLCB4ID0gIkR1cmF0aW9uIiwgeSA9ICJQcmljZSIsIGNvbG9yID0gIkNsYXNzIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKClRoZSBzY2F0dGVyLWRlbnNpdHkgcGxvdCBmb3IgYnVzaW5lc3MtY2xhc3MgZmxpZ2h0IHRpY2tldHMgcmV2ZWFscyB0d28gbWFpbiBjbHVzdGVycyBvZiBwb2ludHMuIFRoZXNlIGNsdXN0ZXJzIGFyZSBjZW50ZXJlZCBhcm91bmQgMjUsMDAwIGFuZCA2MCwwMDAgUnVwZWVzLiBCb3RoIGNsdXN0ZXJzIGZhbGwgd2l0aGluIHRoZSBkdXJhdGlvbiByYW5nZSBvZiAwIHRvIDIwIGhvdXJzLiBUaGUgdHJlbmQgbGluZSBpbiB0aGUgZ3JhcGggaGlnaGxpZ2h0cyBhIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGZsaWdodCBkdXJhdGlvbiBhbmQgdGlja2V0IHByaWNlLCB3aGVyZSBsb25nZXIgZmxpZ2h0cyBnZW5lcmFsbHkgaGF2ZSBoaWdoZXIgcHJpY2VzIGZvciBidXNpbmVzcy1jbGFzcyB0aWNrZXRzLgoKYGBge3J9CiMgR2V0IHRoZSBlbnRyaWVzIGZvciBidXNpbmVzcy1jbGFzcyBmbGlnaHQgdGlja2V0cwpkZl9idXNpbmVzcyA8LSBkZiAlPiUgZmlsdGVyKGNsYXNzID09ICJCdXNpbmVzcyIpCgojIFBsb3QgaGV4YWdvbmFsIGhlYXRtYXAgdG8gaW52ZXN0aWdhdGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGR1cmF0aW9uIGFuZCB0aGUgcHJpY2VzIG9mIEJ1c2luZXNzIGNsYXNzIGZsaWdodHMKZ2dwbG90KGRmX2J1c2luZXNzLCBhZXMoeCA9IGR1cmF0aW9uLCB5ID0gcHJpY2UpKSArIAogIGdlb21fcG9pbnRkZW5zaXR5KHNpemUgPSAwLjUsIGFscGhhID0gMC41KSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIkJ1c2luZXNzIENsYXNzJ3MgRHVyYXRpb24gdnMgUHJpY2UiLCB4ID0gIkR1cmF0aW9uIiwgeSA9ICJQcmljZSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgpTaW1pbGFyIHRvIHRoZSBzY2F0dGVyLWRlbnNpdHkgcGxvdCBmb3IgYnVzaW5lc3MtY2xhc3MgZmxpZ2h0IHRpY2tldHMsIHRoZSBncmFwaCBoYXMgdHdvIG1haW4gY2x1c3RlcnMgZm9yIGVjb25vbXktY2xhc3MgZmxpZ2h0IHRpY2tldHMuIE9uZSBjbHVzdGVyIGlzIGxvY2F0ZWQgYXJvdW5kIHRoZSBwcmljZSBsZXZlbCBvZiAyNTAwIFJ1cGVlcywgYW5kIHRoZSBzZWNvbmQgY2x1c3RlciBpcyBhcm91bmQgNTAsMDAwIFJ1cGVlcy4gTW9zdCBmbGlnaHRzIGhhdmUgZHVyYXRpb25zIHNob3J0ZXIgdGhhbiAyMCBob3VycywgYXMgaW5kaWNhdGVkIGJ5IHRoZSBoaWdoZXIgZGVuc2l0eSBvZiBwb2ludHMgd2l0aGluIHRoaXMgcmFuZ2UuIFRoZSB0cmVuZCBsaW5lLCBzaW1pbGFyIHRvIHRoZSBwcmV2aW91cyBncmFwaCwgaGFzIGEgcG9zaXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gZmxpZ2h0IGR1cmF0aW9uIGFuZCB0aWNrZXQgcHJpY2UuCgpgYGB7cn0KIyBHZXQgdGhlIGVudHJpZXMgZm9yIGVjb25vbXktY2xhc3MgZmxpZ2h0IHRpY2tldHMKZGZfZWNvbm9teSA8LSBkZiAlPiUgZmlsdGVyKGNsYXNzID09ICJFY29ub215IikKCiMgUGxvdCBoZXhhZ29uYWwgaGVhdG1hcCB0byBpbnZlc3RpZ2F0ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZHVyYXRpb24gYW5kIHRoZSBwcmljZXMgb2YgRWNvbm9teSBjbGFzcyBmbGlnaHRzCmdncGxvdChkZl9lY29ub215LCBhZXMoeCA9IGR1cmF0aW9uLCB5ID0gcHJpY2UpKSArIAogIGdlb21fcG9pbnRkZW5zaXR5KHNpemUgPSAwLjUsIGFscGhhID0gMC41KSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIkVjb25vbXkgQ2xhc3MncyBEdXJhdGlvbiB2cyBQcmljZSIsIHggPSAiRHVyYXRpb24iLCB5ID0gIlByaWNlIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKClF1ZXN0aW9uIDM6CgpCZWxvdywgd2UgY3JlYXRlZCBhIHNjYXR0ZXIgcGxvdCB0byBzZWUgaWYgdGhlcmUgaXMgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBkYXlzIGxlZnQgZnJvbSBkZXBhcnR1cmUgZGF0ZSBhbmQgdGhlIHByaWNlIG9mIHRoZSBmbGlnaHQgdGlja2V0LiBGdXJ0aGVyIG1vcmUsIHdlIGFsc28gY2F0ZWdvcml6ZWQgdGhlIHBsb3QgYnkgdGhlIHNvdXJjZSBhbmQgZGVzdGluYXRpb24gY2l0aWVzIHNpbmNlIHdlIGRpZCBub3QgaGF2ZSBpbmRpdmlkdWFsIGZsaWdodCBudW1iZXJzIHRvIHRyYWNrLgoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKCiMgQWRkaW5nIGEgbmV3IGNvbHVtbiAic291cmNlX2Rlc3QiIHdoaWNoIGlzIGEgY29tYmluYXRpb24gb2YgCiMgc291cmNlIGFuZCBkZXN0aW5hdGlvbiBjaXR5CmNvbWJpbmVkX2NpdGllcyA8LSBkZiAlPiUgdW5pdGUoc291cmNlX2Rlc3QsIHNvdXJjZV9jaXR5LCBkZXN0aW5hdGlvbl9jaXR5LCBzZXAgPSAiXyIsIHJlbW92ZSA9IEZBTFNFKQoKIyBEZWZpbmUgdGhlIHBsb3R0aW5nIGZ1bmN0aW9uCnBsb3RfZm9yX2NhdGVnb3J5IDwtIGZ1bmN0aW9uKGNhdCwgZGF0YSkgewogIHN1YnNldF9kYXRhIDwtIHN1YnNldChkYXRhLCBzb3VyY2VfZGVzdCA9PSBjYXQpCiAgCiAgZ2dwbG90KHN1YnNldF9kYXRhLCBhZXMoeCA9IGRheXNfbGVmdCwgeSA9IHByaWNlKSkgKwogICAgZ2VvbV9wb2ludChjb2xvciA9ICJibHVlIikgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAicmVkIikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSBwYXN0ZSgiUGxvdCBmb3IgQ2F0ZWdvcnk6IiwgY2F0KSwKICAgICAgeCA9ICJEYXlzIGJlZm9yZSBEZXBhcnR1cmUiLAogICAgICB5ID0gIlByaWNlIChSdXBlZXMpIgogICAgKSArCiAgICB0aGVtZV9taW5pbWFsKCkKfQoKIyBHZXQgdW5pcXVlIGNhdGVnb3JpZXMKdW5pcXVlX2NhdGVnb3JpZXMgPC0gdW5pcXVlKGNvbWJpbmVkX2NpdGllcyRzb3VyY2VfZGVzdCkKCiMgR2VuZXJhdGUgYW5kIHN0b3JlIHBsb3RzIGZvciBlYWNoIGNhdGVnb3J5CnBsb3RzIDwtIGxhcHBseSh1bmlxdWVfY2F0ZWdvcmllcywgZnVuY3Rpb24oY2F0KSBwbG90X2Zvcl9jYXRlZ29yeShjYXQsIGNvbWJpbmVkX2NpdGllcykpCgojIERpc3BsYXkgYWxsIHBsb3RzIApmb3IgKHBsb3QgaW4gcGxvdHMpIHsKICBwbG90ICsgeWxpbSgwLCAxMDAwMDApCiAgcHJpbnQocGxvdCkKfQpgYGAKCiMjIE1hY2hpbmUgTGVhcm5pbmcgTW9kZWxzCgpGaXJzdCwgd2Ugd2lsbCBiZSBzcGxpdHRpbmcgdGhlIGRhdGFzZXQgaW50byB0aGUgdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc2V0IHRvIGJ1aWxkIG91ciBtYWNoaW5lIGxlYXJuaW5nIG1vZGVscy4gVGhlIHRyYWluaW5nIHNldCB3aWxsIGhhdmUgNzAgcGVyY2VudCBvZiB0aGUgZGF0YXNldCBhbmQgdGhlIHRlc3Rpbmcgc2V0IHdpbGwgaGF2ZSAzMCBwZXJjZW50IG9mIHRoZSBkYXRhc2V0LiBXZSBhbHNvIGNob3NlIHRvIGNyZWF0ZSBhIHNhbXBsZSB0cmFpbmluZyBkYXRhIG9mIDEwMDAwIHJvd3MsIGFzIGl0IHdhcyB0YWtpbmcgb3VyIGNvbXB1dGVycyB0b28gbG9uZyB0byBjb21wdXRlIHRoZSBtb2RlbHMgdXNpbmcgdGhlIGxhcmdlciBkYXRhc2V0LgoKYGBge3J9CnNldC5zZWVkKDEyMykKc21wX3NpemUgPC0gZmxvb3IoMC43ICogbnJvdyhkZikpCnJvd19pbmRleCA8LSBzYW1wbGUoMTogbnJvdyhkZiksIHNpemUgPSBzbXBfc2l6ZSkKdHJhaW5fc21wIDwtIGRmW3Jvd19pbmRleCwgXQp0ZXN0X3NtcCA8LSBkZlstcm93X2luZGV4LCBdCnNhbXBsZV9kYXRhIDwtIHRyYWluX3NtcFtzYW1wbGUobnJvdyh0cmFpbl9zbXApLCAxMDAwMCksIF0KYGBgCgojIyMgVHJlZS1CYXNlZCBNb2RlbHMKClRoZSBmaXJzdCBtb2RlbCB3ZSBhcmUgdXNpbmcgdG8gcHJlZGljdCB0aGUgZmxpZ2h0IHByaWNlcyBpcyB0aGUgdHJlZS1iYXNlZCBtb2RlbC4gSW4gdGhlIG1vZGVsLCB3ZSB1c2VkIGNhdGVnb3JpY2FsIHZhcmlhYmxlIHN1Y2ggYXMgZGVwYXJ0dXJlIHRpbWUgb2YgdGhlIGZsaWdodCBhbmQgY29udGludW91cyB2YXJpYWJsZXMgc3VjaCBhcyBkdXJhdGlvbiBvZiB0aGUgZmxpZ2h0cyBhbmQgZGF5cyBsZWZ0IHRpbGwgdGhlIGRheSBvZiB0aGUgZmxpZ2h0LiBIb3dldmVyLCB0aGlzIG1vZGVsIGRpZCBub3QgZG8gd2VsbCBpbiBwcmVkaWN0aW5nIHRoZSBwcmljZXMgYXMgdGhlIG1lYW4gYWJzb2x1dGUgZXJyb3IgaXMgaGlnaCBhbmQgY29ycmVsYXRpb24gaXMgd2Vhay4KCmBgYHtyfQojIFRyZWUtQmFzZWQgTW9kZWxzCmFyIDwtIHJwYXJ0KHByaWNlIH4gZGVwYXJ0dXJlX3RpbWUgKyBkdXJhdGlvbiArIGRheXNfbGVmdCwgCiAgICAgICAgICAgIHRyYWluX3NtcCkKcHJlZHMgPC0gcHJlZGljdChhciwgdGVzdF9zbXApCgojIENhbGN1bGF0ZSBNZWFuIEFic29sdXRlIEVycm9yIChNQUUpCm1hZSA8LSBtZWFuKGFicyhwcmVkcyAtIHRlc3Rfc21wJHByaWNlKSkKbWFlCgojIENhbGN1bGF0ZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudApjciA8LSBjb3IocHJlZHMsdGVzdF9zbXAkcHJpY2UpCmNyCgojIEdldCB0aGUgb3B0aW1hbCBjcCB2YWx1ZQpvcHRpbWFsX2NwIDwtIGFyJGNwdGFibGVbd2hpY2gubWluKGFyJGNwdGFibGVbLCJ4ZXJyb3IiXSksICJDUCJdCgojIFBydW5lIHRoZSB0cmVlCnBydW5lZF90cmVlIDwtIHBydW5lKGFyLCBjcCA9IG9wdGltYWxfY3ApCgojIFZpc3VhbGl6ZSB0aGUgdHJlZQpycGFydC5wbG90KHBydW5lZF90cmVlLCBib3gucGFsZXR0ZSA9ICJCbHVlcyIsIG1haW4gPSAiU2ltcGxpZmllZCBEZWNpc2lvbiBUcmVlIikKYGBgCgpUbyBtYWtlIHRoZSBtb2RlbCBtb3JlIGFjY3VyYXRlLCB3ZSB0cmFpbmVkIHRoZSB0cmVlLWJhc2VkIG1vZGVsIHdpdGggbW9yZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMuIEFmdGVyIHJldHJhaW5pbmcgdGhlIG1vZGVsLCB0aGUgbW9kZWwgbm93IHByb2R1Y2UgcHJlZGljdGlvbnMgd2l0aCBleHRyZW1lbHkgc3Ryb25nIGNvcnJlbGF0aW9uIGFuZCBsb3dlciBtZWFuIGFic29sdXRlIGVycm9yIGNvbXBhcmUgdG8gdGhlIGxhc3QgbW9kZWwuCgpgYGB7cn0KIyBUcmFpbiBtb2RlbCB3aXRoIG1vcmUgdmFyaWFibGVzCmFyMiA8LSBycGFydChwcmljZSB+IGRlcGFydHVyZV90aW1lICsgZHVyYXRpb24gKyBkYXlzX2xlZnQgKyBzdG9wcyArIHNvdXJjZV9jaXR5ICsgYWlybGluZSArIGNsYXNzICsgZGVzdGluYXRpb25fY2l0eSwKICAgICAgICAgICAgdHJhaW5fc21wKQpwcmVkcyA8LSBwcmVkaWN0KGFyMiwgdGVzdF9zbXApCgojIENhbGN1bGF0ZSBNZWFuIEFic29sdXRlIEVycm9yIChNQUUpCm1hZSA8LSBtZWFuKGFicyhwcmVkcyAtIHRlc3Rfc21wJHByaWNlKSkKbWFlCgojIENhbGN1bGF0ZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudApjciA8LSBjb3IocHJlZHMsdGVzdF9zbXAkcHJpY2UpCmNyCmBgYAoKVGhlIHBsb3Qgc2hvd3MgdGhhdCB0aGUgZmxpZ2h0IGNsYXNzIGlzIHRoZSBtYWluIHByZWRpY3RvciBvZiB0aGUgZmxpZ2h0IHRpY2tldCdzIHByaWNlLiBUaGUgZHVyYXRpb24gb2YgdGhlIGZsaWdodCBmdXJ0aGVyIGluZmx1ZW5jZXMgdGhlIHByaWNlIG9mIHRoZSBidXNpbmVzcyBjbGFzcyBmbGlnaHQuCgpgYGB7cn0KIyBHZXQgdGhlIG9wdGltYWwgY3AgdmFsdWUKb3B0aW1hbF9jcDIgPC0gYXIyJGNwdGFibGVbd2hpY2gubWluKGFyMiRjcHRhYmxlWywieGVycm9yIl0pLCAiQ1AiXQoKIyBQcnVuZSB0aGUgdHJlZQpwcnVuZWRfdHJlZTIgPC0gcHJ1bmUoYXIyLCBjcCA9IG9wdGltYWxfY3AyKQoKIyBWaXN1YWxpemUgdGhlIHRyZWUKcnBhcnQucGxvdChwcnVuZWRfdHJlZTIsIGJveC5wYWxldHRlID0gIkJsdWVzIiwgbWFpbiA9ICJTaW1wbGlmaWVkIERlY2lzaW9uIFRyZWUiKQpgYGAKCiMjIExpbmVhciBNb2RlbHMKClRoZSBuZXh0IG1vZGVsIHdlIHdpbGwgYmUgdXNpbmcgdG8gcHJlZGljdCBmbGlnaHQgcHJpY2VzIHdpbGwgYmUgYSBsaW5lYXIgbW9kZWwuCgpgYGB7cn0KIyBSZW1vdmUgRmxpZ2h0IGNvbHVtbiBmcm9tIGRhdGEgZnJhbWUKc2FtcGxlX2RhdGEgPC0gc3Vic2V0KHNhbXBsZV9kYXRhLCBzZWxlY3QgPSAtYyhmbGlnaHQpKQoKI0dldCBmb3JtdWxhIGZvciBMTQpkZXBlbmRlbnRfdmFycyA8LSBzZXRkaWZmKG5hbWVzKHNhbXBsZV9kYXRhKSwgInByaWNlIikKZm9ybXVsYSA8LSBhcy5mb3JtdWxhKHBhc3RlKCJwcmljZSB+IiwgcGFzdGUoZGVwZW5kZW50X3ZhcnMsIGNvbGxhcHNlID0gIiArICIpKSkKCiMgQnVpbGQgdGhlIGxpbmVhciBtb2RlbApsaW5lYXJfbW9kZWwgPC0gbG0oZm9ybXVsYSwgZGF0YSA9IHNhbXBsZV9kYXRhKQpgYGAKCmBgYHtyfQojIEdldCBwcmVkaWN0aW9ucyBhbmQgTUFFCmxtX3ByZWRzIDwtIHByZWRpY3QobGluZWFyX21vZGVsLCB0ZXN0X3NtcCkKbG1fbWFlIDwtIG1lYW4oYWJzKGxtX3ByZWRzIC0gdGVzdF9zbXAkcHJpY2UpKQpsbV9tYWUKCiMgQ2FsY3VsYXRlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50CmxtX2NyIDwtIGNvcihsbV9wcmVkcyx0ZXN0X3NtcCRwcmljZSkKbG1fY3IKYGBgCgojIyBTdXBwb3J0IFZlY3RvciBNYWNoaW5lCgpTdXBwb3J0IHZlY3RvciBtYWNoaW5lIGlzIG9uZSBvZiB0aGUgbW9kZWwgd2UgYXJlIHVzaW5nIHRvIHByZWRpY3QgdGhlIHByaWNlIG9mIHRoZSBwbGFuZSB0aWNrZXRzLiBJbmRlcGVuZGVudCB2YXJpYWJsZXMgc3VjaCBhcyBkZXBhcnR1cmUgdGltZSBvZiB0aGUgZmxpZ2h0LCBkdXJhdGlvbiBvZiB0aGUgZmxpZ2h0LCBkYXlzIGxlZnQgdG8gdGhlIGZsaWdodCwgbnVtYmVyIG9mIHN0b3BzLCBzb3VyY2UgY2l0eSwgYWlybGluZSwgY2xhc3MsIGFuZCBkZXN0aW5hdGlvbl9jaXR5IGFyZSB1c2VkIHRvIHByZWRpY3QgdGhlIHByaWNlIG9mIHRoZSBmbGlnaHQgdGlja2V0cy4gVGhyZWUgZGlmZmVyZW50IGtlcm5lbCB3ZXJlIHVzZWQgdG8gZmluZCB0aGUgc3VpdGFibGUgbW9kZWwuIFRoZSByYWRpYWwgU1ZNIG1vZGVsIHBlcmZvcm1lZCB0aGUgYmVzdCBpbiBwcmVkaWN0aW5nIHRoZSBmbGlnaHQgcHJpY2VzIGFzIHRoZSBtb2RlbCBoYXMgdGhlIHNtYWxsZXN0IG1lYW4gYWJzb2x1dGUgZXJyb3IgYW5kIGhpZ2hlc3QgY29ycmVsYXRpb24gY29lZmZpY2llbnQuCgpgYGB7cn0KIyBsaW5lYXIgc3ZtIG1vZGVsCnMgPC0gc3ZtKHByaWNlIH4gZGVwYXJ0dXJlX3RpbWUgKyBkdXJhdGlvbiArIGRheXNfbGVmdCArIHN0b3BzICsgc291cmNlX2NpdHkgKyBhaXJsaW5lICsgY2xhc3MgKyBkZXN0aW5hdGlvbl9jaXR5LCAKICAgICAgICAgc2FtcGxlX2RhdGEsIAogICAgICAgICBrZXJuZWw9ImxpbmVhciIpCnNfcHJlZHMgPC0gcHJlZGljdChzLCB0ZXN0X3NtcCkKbWFlX3MgPC0gbWVhbihhYnMoc19wcmVkcyAtIHRlc3Rfc21wJHByaWNlKSkKbWFlX3MKY3JfcyA8LSBjb3Ioc19wcmVkcyx0ZXN0X3NtcCRwcmljZSkKY3JfcwoKIyByYWRpYWwgc3ZtIG1vZGVsCnIgPC0gc3ZtKHByaWNlIH4gZGVwYXJ0dXJlX3RpbWUgKyBkdXJhdGlvbiArIGRheXNfbGVmdCArIHN0b3BzICsgc291cmNlX2NpdHkgKyBhaXJsaW5lICsgY2xhc3MgKyBkZXN0aW5hdGlvbl9jaXR5LCAKICAgICAgICAgc2FtcGxlX2RhdGEsIAogICAgICAgICBrZXJuZWw9InJhZGlhbCIpCnJfcHJlZHMgPC0gcHJlZGljdChyLCB0ZXN0X3NtcCkKbWFlX3IgPC0gbWVhbihhYnMocl9wcmVkcyAtIHRlc3Rfc21wJHByaWNlKSkKbWFlX3IKY3JfciA8LSBjb3Iocl9wcmVkcyx0ZXN0X3NtcCRwcmljZSkKY3JfcgoKIyBwb2x5IHN2bSBtb2RlbApwb2x5IDwtIHN2bShwcmljZSB+IGRlcGFydHVyZV90aW1lICsgZHVyYXRpb24gKyBkYXlzX2xlZnQgKyBzdG9wcyArIHNvdXJjZV9jaXR5ICsgYWlybGluZSArIGNsYXNzICsgZGVzdGluYXRpb25fY2l0eSwgCiAgICAgICAgICAgIHNhbXBsZV9kYXRhLCAKICAgICAgICAgICAga2VybmVsPSJwb2x5bm9taWFsIikKcG9seV9wcmVkcyA8LSBwcmVkaWN0KHBvbHksIHRlc3Rfc21wKQptYWVfcCA8LSBtZWFuKGFicyhwb2x5X3ByZWRzIC0gdGVzdF9zbXAkcHJpY2UpKQptYWVfcApjcl9wIDwtIGNvcihwb2x5X3ByZWRzLHRlc3Rfc21wJHByaWNlKQpjcl9wCmBgYAoKQWZ0ZXIgdHVuaW5nIHRoZSByYWRpYWwgU1ZNIG1vZGVsLCB0aGUgbW9kZWwgYmVjYW1lIG1vcmUgYWNjdXJhdGUgYXMgdGhlIG1lYW4gYWJzb2x1dGUgZXJyb3IgZGVjcmVhc2VkIGFuZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgaW5jcmVhc2VkLiBUaGUgYmVzdCBwYXJhbWV0ZXJzIGZvciBnYW1tYSBhbmQgY29zdCBhcmUgMC4xIGFuZCAxMCwgcmVzcGVjdGl2ZWx5LiBBIHNtYWxsZXIgcmFuZG9tIHN1YnNldCBvZiA1MDAwIGVudHJpZXMgd2FzIHVzZWQgdG8gdHJhaW4gdGhlIGZpbmUtdHVuZWQgbW9kZWwgZm9yIGVmZmljaWVuY3kuCgpgYGB7cn0KIyBUYWtlIGEgc21hbGxlciBzYW1wbGUKc2FtcGxlX2RhdGEyIDwtIHRyYWluX3NtcFtzYW1wbGUobnJvdyh0cmFpbl9zbXApLCA1MDAwKSwgXQoKIyBGaW5kIHRoZSBiZXN0IHBhcmFtZXRlcnMKcCA8LSB0dW5lLnN2bShwcmljZSB+IGRlcGFydHVyZV90aW1lICsgZHVyYXRpb24gKyBkYXlzX2xlZnQgKyBzdG9wcyArIHNvdXJjZV9jaXR5ICsgYWlybGluZSArIGNsYXNzICsgZGVzdGluYXRpb25fY2l0eSwgCiAgICAgICAgICAgICAgZGF0YSA9IHNhbXBsZV9kYXRhMiwgCiAgICAgICAgICAgICAgZ2FtbWE9YygwLjAxLCAwLjEsIDEpLCAKICAgICAgICAgICAgICBjb3N0PWMoMSwgNSwgMTApICwgCiAgICAgICAgICAgICAga2VybmVsID0gInJhZGlhbCIpIAoKIyBUcmFpbiB0aGUgbW9kZWwgd2l0aCB0aGUgYmVzdCBwYXJhbWV0ZXJzCm5ld19yIDwtIHN2bShwcmljZSB+IGRlcGFydHVyZV90aW1lICsgZHVyYXRpb24gKyBkYXlzX2xlZnQgKyBzdG9wcyArIHNvdXJjZV9jaXR5ICsgYWlybGluZSArIGNsYXNzICsgZGVzdGluYXRpb25fY2l0eSwgCiAgICAgICAgICAgICBzYW1wbGVfZGF0YSwgCiAgICAgICAgICAgICBrZXJuZWw9InJhZGlhbCIsIAogICAgICAgICAgICAgZ2FtbWE9cCRiZXN0LnBhcmFtZXRlcnMkZ2FtbWEsIAogICAgICAgICAgICAgY29zdD1wJGJlc3QucGFyYW1ldGVycyRjb3N0KQpuZXdfcl9wcmVkcyA8LSBwcmVkaWN0KG5ld19yLCB0ZXN0X3NtcCkKCiMgQ2FsY3VsYXRlIE1lYW4gQWJzb2x1dGUgRXJyb3IgKE1BRSkKbmV3X21hZV9yIDwtIG1lYW4oYWJzKG5ld19yX3ByZWRzIC0gdGVzdF9zbXAkcHJpY2UpKQpuZXdfbWFlX3IKCiMgQ2FsY3VsYXRlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50Cm5ld19jcl9yIDwtIGNvcihuZXdfcl9wcmVkcyx0ZXN0X3NtcCRwcmljZSkKbmV3X2NyX3IKYGBgCgojIyBDb25jbHVzaW9uCgpGb3IgdGhpcyBwcm9qZWN0IHdlIHNvdWdodCBvdXQgdG8gc2VlIGlmIHRoZXJlIGFyZSBmYWN0b3JzIGluZmx1ZW5jaW5nIHRoZSBmbGlnaHQgcHJpY2VzLiBGb3Igb3VyIGZpcnN0IHF1ZXN0aW9uLCB3ZSBhc2sgaWYgdGhlcmUgd2FzIGEgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgdGltZSBvZiBkZXBhcnR1cmUgYW5kIHRoZSBwcmljZSBvZiB0aGUgdGlja2V0cy4gRnJvbSBhIG51bWJlciBvZiB2aXN1YWxpemF0aW9ucyB0aGF0IHdlIGRpZCwgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIGlzIGRlZmluaXRlbHkgYSBjb3JyZWxhdGlvbiBhcyBsYXRlIG5pZ2h0IHRpY2tldHMgYXJlIHVzdWFsbHkgdGhlIGNoZWFwZXN0IHdpdGggdmVyeSBsaXR0bGUgdmFyaWFiaWxpdHkgaW4gcHJpY2Ugd2l0aCBhIG1lYW4gcHJpY2Ugb2YgOTI5NS4zIFJ1cGVlcy4gRm9yIHRoZSByZW1haW5pbmcgZGVwYXJ0dXJlIHRpbWVzLCB3ZSBjYW4gc2VlIHRoYXQgdGhlcmUgaXMgbm90IG11Y2ggZGlmZmVyZW5jZSBpbiBwcmljZXMgYXMgdGhlIG1lYW5zIG9mIHRoZSByZXN0IG9mIHRoZSBkZXBhcnR1cmUgdGltZXMgY2VudGVyIGFyb3VuZCAyMTAwMCBSdXBlZXMuCgpGb3Igb3VyIHNlY29uZCBxdWVzdGlvbiwgd2UgdHJpZWQgdG8gc2VlIGlmIHRoZXJlIHdhcyBhIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGR1cmF0aW9uIG9mIHRoZSBmbGlnaHQgYW5kIHRoZSB0aWNrZXQgb2YgdGhlIHByaWNlLiBGcm9tIGp1c3QgbG9va2luZyBhIHRoZSB0cmVuZCBsaW5lIGZyb20gdGhlIHNjYXR0ZXIgcGxvdCwgd2UgY2FuIHNlZSBhIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGR1cmF0aW9uIGFuZCB0aGUgcHJpY2Ugb2YgdGhlIHRpY2tldC4gVXBvbiBmdXJ0aGVyIGluc3BlY3Rpb24gb2YgdGhlIHNjYXR0ZXIgcGxvdCwgYWZ0ZXIgZGlmZmVyZW50aWF0aW5nIHRoZSBjbGFzc2VzIG9mIHRoZSB0aWNrZXRzLCB3ZSBjYW4gc2VlIHRoZSBidXNpbmVzcyBjbGFzcyB0aWNrZXRzIGdldCBldmVuIG1vcmUgZXhwZW5zaXZlIHdpdGggZHVyYXRpb24gdGhhbiBlY29ub215IHRpY2tldHMuCgpGb3Igb3VyIGxhc3QgcXVlc3Rpb24sIHdlIHdhbnRlZCB0byBzZWUgaWYgdGhlcmUgd2FzIGEgcmVsYXRpb24gYmV0d2VlbiB0aGUgZGF5cyBsZWZ0IGZyb20gZGVwYXJ0dXJlIGFuZCB0aGUgcHJpY2Ugb2YgdGhlIHRpY2tldC4gV2UgdXNlZCBhIHNjYXR0ZXIgcGxvdCBjYXRlZ29yaXplZCBieSBzb3VyY2UgYW5kIGRlc3RpbmF0aW9uIGNpdHkgYW5kIGZvciBldmVyeSBwbG90IHdlIGNhbiBzZWUgdGhhdCB0aGVyZSBpcyBhIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHByaWNlIGFuZCB0aGUgZGF5cyBsZWZ0IGZyb20gZGVwYXJ0dXJlLCB0aGUgZnVydGhlciB0aGUgZGVwYXJ0dXJlIGRhdGUgaXMgdGhlIGNoZWFwZXIgdGhlIHRpY2tldHMuCgpGb3Igb3VyIGZpcnN0IHRyZWUgbW9kZWwsIHdlIHVzZWQgb25seSAzIGluZGVwYW5kZW50IHZhcmlhYmxlcyAoZGVwYXJ0dXJlIHRpbWUsIGR1cmF0aW9uLCBkYXlzX2xlZnQpIHdpdGggb3VyIHRhcmdldCB2YXJpYWJsZSwgcHJpY2UsIHRvIHRyYWluIG91ciBtb2RlbC4gVGhpcyBkaWQgbm90IGxlYWQgdG8gb3B0aW1hbCByZXN1bHRzIGFzIHdlIGdvdCBhIG1lYW4gYWJzb2x1dGUgZXJyb3Igb2YgMTg4NzkuNCBhbmQgYSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBvZiAwLjI1OTIuIFNvIGZvciBvdXIgc2Vjb25kIHRyZWUgbW9kZWwsIHdlIHVzZWQgYWxsIHRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgc2V0IHRvIHRyYWluIHRoZSBtb2RlbCBhbmQgd2UgcmVjZWl2ZWQgYmV0dGVyIHJlc3VsdHMgd2l0aCBhIG1lYW4gYWJzb2x1dGUgZXJyb3Igb2YgNDMxNS4xNzYgYW5kIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgMC45NTcuCgpGb3Igb3VyIGxpbmVhciBtb2RlbCwgd2UgdXNlZCBhbGwgdGhlIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSBzZXQgdG8gdHJhaW4gdGhlIG1vZGVsIGFuZCBhIG1lYW4gYWJzb2x1dGUgZXJyb3Igb2YgNDU2MC4yOTggYW5kIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgMC45NTQuCgpGb3Igb3VyIFNWTXMsIGZpcnN0IHdlIHRyYWluZWQgMSBsaW5lYXIgU1ZNLCAxIHJhZGlhbCBTVk0gYW5kIDEgcG9seW5vbWlhbCBTVk0gdXNpbmcgYWxsIHRoZSB2YXJpYWJsZXMgZnJvbSB0aGUgZGF0YXNldC4gVGhlIHRhYmxlIGJlbG93IHNob3dzIHRoZSBtZWFuIGFic29sdXRlIHZhbHVlIGFuZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgZm9yIGVhY2ggb2YgdGhlc2UgbW9kZWxzLgoKYGBgICAgICAgICAgCiAgICAgICAgICAgICAgICBNZWFuIGFic29sdXRlIHZhbHVlICAgICAgICAgQ29ycmVsYXRpb24gY29lZmZpY2llbnQgCkxpbmVhciBTVk0gICAgICAgNDE4My4zNzUgICAgICAgICAgICAgICAgICAgICAgICAgMC45NTE0MjA2ICAgICAgICAgICAgICAgICAgICAgICAgClJhZGlhbCBTVk0gICAgICAgMzEzOS43MjcgICAgICAgICAgICAgICAgICAgICAgICAgMC45NzMxNzM5ICAgICAgICAgICAgICAgICAgICAgICAKUG9seW5vbWlhbCBTVk0gICA3NzM5LjgzMiAgICAgICAgICAgICAgICAgICAgICAgICAwLjkxNTY4ICAgICAgICAgICAKYGBgCgpXZSBkZWNpZGVkIHRvIHR1bmUgdGhlIFJhZGlhbCBTVk0gdG8gbWFrZSBpdCBtb3JlIGFjY3VyYXRlIGJ5IHVzaW5nIHRoZSBiZXN0IGdhbW1hIGFuZCBjb3N0IHZhbHVlcy4gQWZ0ZXIgdHVuaW5nIHRoZSBtb2RlbHMsIHRoZSBNQUUgZGVjcmVhc2VkIHRvIDI4NTEuNzA0IGFuZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgcm9zZSB0byAwLjk3ODMuCgpBZnRlciBldmFsdWF0aW5nIGFsbCBvdXIgbW9kZWxzLCB3ZSBjYW4gc2VlIHRoYXQgUmFkaWFsIFNWTSBoYXMgdGhlIGJlc3QgcGVyZm9ybWFuY2Ugb3ZlcmFsbCBldmVuIGJlZm9yZSB0aGUgdHVuaW5nIHdpdGggYSBNQUUgb2YgMzEzOS43MjcgYW5kIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgMC45NzMuCgpGcm9tIHRoaXMgcHJvamVjdCwgd2UgY2FuIGNvbmNsdWRlIHRoYXQgdGhlcmUgYXJlIGRlZmluaXRlbHkgZmFjdG9ycyBzdWNoIGFzIGRlcGFydHVyZSB0aW1lLCBkdXJhdGlvbiBhbmQgdGhlIGRheXMgbGVmdCBmcm9tIGRlcGFydHVyZSBhZmZlY3RpbmcgdGhlIHByaWNlIG9mIGZsaWdodCB0aWNrZXRzLgoKQ2l0YXRpb25zCgpbMV0gamFuLWdseCwg4oCcU2NhdHRlcnBsb3Qgd2l0aCB0b28gbWFueSBwb2ludHMs4oCdIFN0YWNrIE92ZXJmbG93LCBPY3QuIDEwLCAyMDExLiA8aHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNzcxNDY3Ny9zY2F0dGVycGxvdC13aXRoLXRvby1tYW55LXBvaW50cy81ODUyMzk1NiM1ODUyMzk1Nj4KClsyXSDigJxIb3cgdG8gUHJ1bmUgYSBUcmVlIGluIFI/LOKAnSBHZWVrc2ZvckdlZWtzLCBKdW4uIDEzLCAyMDI0LiA8aHR0cHM6Ly93d3cuZ2Vla3Nmb3JnZWVrcy5vcmcvaG93LXRvLXBydW5lLWEtdHJlZS1pbi1yLz4KClszXSA8aHR0cHM6Ly93d3cuaWNhby5pbnQvYW5udWFsLXJlcG9ydC0yMDE5L1BhZ2VzL3RoZS13b3JsZC1vZi1haXItdHJhbnNwb3J0LWluLTIwMTkuYXNweCM+Olx+OnRleHQ9VGhlJTIwNC41JTIwYmlsbGlvbiUyMHNjaGVkdWxlZCUyMHBhc3NlbmdlcnMsc29tZSUyMDkwJTIwbWlsbGlvbiUyMGluJTIwMjA0MC4mdGV4dD1UaGUlMjB3b3JsZCdzJTIwbWFqb3IlMjBtYW51ZmFjdHVyZXJzJTIwZGVsaXZlcmVkLDgyMiUyMG5ldyUyMGFpcmNyYWZ0JTIwbmV0JTIwb3JkZXJzLgo=